#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <cstring>

#include "Socket.hpp"
#include "log.hpp"
#include "Epoller.hpp"

const static int backlog = 32;
const static int max_events = 64;

class Epollserver
{
    std::unique_ptr<Net_work::Socket> _listensock;
    std::unique_ptr<Epoll::Epoller> _epoller;
    int _port;
    bool _isrunning;
    struct epoll_event _revs[max_events];

public:
    Epollserver(int port) : _port(port), _listensock(new Net_work::TcpSocket()), _isrunning(false), _epoller(new Epoll::Epoller())
    {
        lg.LogMessage(Info, "Init socket success,epfd\n");
    }

    ~Epollserver()
    {
    }

    bool InitServer()
    {
        _listensock->BuildListenSocket(_port, backlog);
        lg.LogMessage(Info, "Init socket success, listensock is :%d\n", _listensock->GetSockFd());

        _epoller->InitEoller();
        lg.LogMessage(Info, "Init epoller success\n");

        _epoller->AddEvent(_listensock->GetSockFd(), EPOLLIN); //! 添加监听事件
        return true;
    }

    void HandlerEvent(int n)
    {
        lg.LogMessage(Debug, "%d 个 ");
        for (int i = 0; i < n; i++)
        {
            lg.LogMessage(Debug, "ready fd: %d, Event is :%u \n", _revs[i].data.fd, _revs[i].events);
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;

            if (events & EPOLLIN)
            {
                // 读事件分两种
                if (sockfd == _listensock->GetSockFd())
                {
                    // 监听事件就绪
                    std::string clientip;
                    uint16_t clientport;

                    if (!Accepter(&clientip, &clientport))
                    {
                        // 如果失败,就 continue 继续
                        continue;
                    }
                    lg.LogMessage(Info, "accept client success\n");
                }
                else
                {
                    std::string message;

                    // ! 注意, telnet 输入的消息在结尾的时候,是以 \r\n 结尾的
                    int n = Recver(sockfd, &message);

                    if (n > 0)
                    {
                        std::cout << "client# " << message << std::endl;
                        std::string server_message = "server say# " + message;
                        send(sockfd, server_message.c_str(), server_message.size(), 0);
                    }
                    else
                    {
                        if (n == 0) // 关闭连接
                        {
                            lg.LogMessage(Info, "client %d close \n", sockfd);
                        }
                        else // 出现错误
                        {
                            lg.LogMessage(Info, "recv %d error \n", sockfd);
                        }
                        // 将事件从 epoller 中删除
                        _epoller->DelEvent(sockfd); //! 注意 epoll模型中,删除的文件描述符必须是合法的

                        ::close(sockfd); // 对方关闭连接
                    }
                }
            }
        }
    }

    int Recver(int fd, std::string *out)
    {
        char buffer[1024];
        int n = ::recv(fd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }

    bool Accepter(std::string *peerip, uint16_t *peerport)
    {

        Net_work::Socket *s = _listensock->AcceptConnection(peerip, peerport);

        if (s->GetSockFd() < 0)
        {
            lg.LogMessage(Warning, "accept error! \n");
            return false;
        }

        // 添加新事件
        _epoller->AddEvent(s->GetSockFd(), EPOLLIN);
        return true;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 设置阻塞等待时间
            int timeout = 1000; // 1 秒

            int n = _epoller->Wait(_revs, max_events, timeout);
            // sleep(5);

            switch (n)
            {
            case 0:
                lg.LogMessage(Debug, "timeout ...\n");
                break;
            case -1:
                lg.LogMessage(Error, "epoll wait faild!\n");
                break;
            default:
                lg.LogMessage(Info, "event happy...\n");

                // !  epoll 默认是 LT模式,如果有消息到来,上层层没有处理,epoll就会疯狂提醒上层
                HandlerEvent(n);
                break;
            }
        }
        _isrunning = false;
    }
};